<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>视频字幕合成工具</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/ffmpeg/0.11.6/ffmpeg.min.js"></script>
    <style>
      * {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
        font-family: 'SF Pro Display', 'PingFang SC', 'Helvetica Neue', Arial,
          sans-serif;
      }

      :root {
        --primary-bg: #e6e7ee;
        --secondary-bg: #ffffff;
        --shadow-light: #ffffff;
        --shadow-dark: #d1d9e6;
        --accent-color: #667eea;
        --accent-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        --success-color: #4ecdc4;
        --danger-color: #ff6b6b;
        --warning-color: #feca57;
        --text-primary: #2d3748;
        --text-secondary: #718096;
        --glass-bg: rgba(255, 255, 255, 0.25);
        --glass-border: rgba(255, 255, 255, 0.18);
      }

      body {
        background: var(--primary-bg);
        color: var(--text-primary);
        min-height: 100vh;
        padding: 20px;
        display: flex;
        flex-direction: column;
        align-items: center;
        transition: all 0.3s ease;
        animation: pageLoad 0.8s ease;
      }

      @keyframes pageLoad {
        from {
          opacity: 0;
          transform: translateY(20px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      .container {
        width: 100%;
        max-width: 1200px;
        background: var(--primary-bg);
        border-radius: 30px;
        padding: 40px;
        box-shadow: 20px 20px 60px var(--shadow-dark),
          -20px -20px 60px var(--shadow-light);
        margin-top: 20px;
        transition: all 0.3s ease;
        animation: containerFloat 1s ease 0.2s both;
      }

      @keyframes containerFloat {
        from {
          opacity: 0;
          transform: translateY(30px) scale(0.95);
        }
        to {
          opacity: 1;
          transform: translateY(0) scale(1);
        }
      }

      .container:hover {
        box-shadow: 25px 25px 70px var(--shadow-dark),
          -25px -25px 70px var(--shadow-light);
      }

      header {
        text-align: center;
        margin-bottom: 40px;
        padding: 30px;
        background: var(--primary-bg);
        border-radius: 25px;
        box-shadow: 10px 10px 20px var(--shadow-dark),
          -10px -10px 20px var(--shadow-light);
        animation: headerSlide 0.8s ease 0.4s both;
      }

      @keyframes headerSlide {
        from {
          opacity: 0;
          transform: translateY(-30px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      h1 {
        font-size: 3.2rem;
        margin-bottom: 15px;
        background: var(--accent-gradient);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
        background-clip: text;
        font-weight: 700;
        animation: titleGlow 3s ease-in-out infinite alternate;
      }

      @keyframes titleGlow {
        from {
          filter: brightness(1);
        }
        to {
          filter: brightness(1.2);
        }
      }

      .subtitle {
        font-size: 1.3rem;
        color: var(--text-secondary);
        margin-bottom: 30px;
        font-weight: 500;
      }

      .panels {
        display: flex;
        gap: 30px;
        margin-bottom: 40px;
        animation: panelsSlide 0.8s ease 0.6s both;
      }

      @keyframes panelsSlide {
        from {
          opacity: 0;
          transform: translateX(-20px);
        }
        to {
          opacity: 1;
          transform: translateX(0);
        }
      }

      .panel {
        flex: 1;
        background: var(--primary-bg);
        border-radius: 25px;
        padding: 30px;
        box-shadow: 12px 12px 24px var(--shadow-dark),
          -12px -12px 24px var(--shadow-light);
        transition: all 0.3s ease;
        position: relative;
        overflow: hidden;
      }

      .panel::before {
        content: '';
        position: absolute;
        top: 0;
        left: -100%;
        width: 100%;
        height: 100%;
        background: linear-gradient(
          90deg,
          transparent,
          rgba(255, 255, 255, 0.1),
          transparent
        );
        transition: left 0.8s;
      }

      .panel:hover::before {
        left: 100%;
      }

      .panel:hover {
        transform: translateY(-5px);
        box-shadow: 16px 16px 32px var(--shadow-dark),
          -16px -16px 32px var(--shadow-light);
      }

      .panel-title {
        font-size: 1.6rem;
        margin-bottom: 25px;
        color: var(--accent-color);
        display: flex;
        align-items: center;
        font-weight: 600;
      }

      .panel-title::before {
        content: attr(data-icon);
        margin-right: 12px;
        font-size: 1.8rem;
        animation: iconBounce 2s ease-in-out infinite;
      }

      @keyframes iconBounce {
        0%,
        100% {
          transform: scale(1);
        }
        50% {
          transform: scale(1.1);
        }
      }

      .file-upload {
        border: 3px dashed var(--accent-color);
        border-radius: 25px;
        padding: 50px 40px;
        text-align: center;
        transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
        margin-bottom: 25px;
        cursor: pointer;
        background: var(--primary-bg);
        box-shadow: inset 8px 8px 16px var(--shadow-dark),
          inset -8px -8px 16px var(--shadow-light);
        position: relative;
        overflow: hidden;
      }

      .file-upload:hover {
        border-color: var(--success-color);
        transform: translateY(-5px) scale(1.02);
        box-shadow: inset 10px 10px 20px var(--shadow-dark),
          inset -10px -10px 20px var(--shadow-light),
          0 15px 40px rgba(102, 126, 234, 0.25), 0 5px 15px rgba(0, 0, 0, 0.1);
      }

      .file-upload.dragover {
        border-color: var(--success-color);
        background: rgba(78, 205, 196, 0.05);
        transform: scale(1.05);
        box-shadow: inset 12px 12px 24px var(--shadow-dark),
          inset -12px -12px 24px var(--shadow-light),
          0 20px 50px rgba(78, 205, 196, 0.3);
        animation: dragPulse 1s ease-in-out infinite;
      }

      @keyframes dragPulse {
        0%,
        100% {
          border-color: var(--success-color);
        }
        50% {
          border-color: var(--accent-color);
        }
      }

      .file-upload-content {
        position: relative;
        z-index: 1;
      }

      .file-upload-icon {
        font-size: 3.5rem;
        margin-bottom: 20px;
        display: block;
        animation: iconFloat 3s ease-in-out infinite;
        filter: drop-shadow(0 4px 8px rgba(102, 126, 234, 0.2));
      }

      @keyframes iconFloat {
        0%,
        100% {
          transform: translateY(0);
        }
        50% {
          transform: translateY(-10px);
        }
      }

      .file-upload-text {
        font-size: 1.4rem;
        font-weight: 600;
        color: var(--text-primary);
        margin-bottom: 10px;
        background: var(--accent-gradient);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
        background-clip: text;
      }

      .file-upload-subtext {
        font-size: 1.1rem;
        color: var(--text-secondary);
        margin-bottom: 20px;
        font-weight: 500;
      }

      .file-upload-formats {
        font-size: 0.9rem;
        color: var(--accent-color);
        font-weight: 500;
        padding: 8px 16px;
        background: rgba(102, 126, 234, 0.1);
        border-radius: 20px;
        display: inline-block;
        margin-bottom: 20px;
      }

      .file-upload input[type='file'] {
        position: absolute;
        width: 100%;
        height: 100%;
        top: 0;
        left: 0;
        opacity: 0;
        cursor: pointer;
        z-index: 2;
      }

      .video-preview {
        width: 100%;
        background: var(--primary-bg);
        border-radius: 20px;
        overflow: hidden;
        margin-top: 20px;
        box-shadow: inset 10px 10px 20px var(--shadow-dark),
          inset -10px -10px 20px var(--shadow-light);
        transition: all 0.3s ease;
      }

      .video-preview:hover {
        box-shadow: inset 12px 12px 24px var(--shadow-dark),
          inset -12px -12px 24px var(--shadow-light);
      }

      video {
        width: 100%;
        max-height: 300px;
        display: block;
        border-radius: 15px;
      }

      .subtitle-info {
        background: var(--primary-bg);
        border-radius: 15px;
        padding: 20px;
        margin-top: 20px;
        box-shadow: inset 6px 6px 12px var(--shadow-dark),
          inset -6px -6px 12px var(--shadow-light);
      }

      .subtitle-info h4 {
        color: var(--accent-color);
        margin-bottom: 10px;
        font-size: 1.1rem;
      }

      .subtitle-info p {
        color: var(--text-secondary);
        margin-bottom: 8px;
        font-size: 0.95rem;
      }

      .form-group {
        margin-bottom: 20px;
      }

      label {
        display: block;
        margin-bottom: 10px;
        color: var(--text-secondary);
        font-weight: 500;
        font-size: 0.95rem;
      }

      input,
      select {
        width: 100%;
        padding: 14px 18px;
        background: var(--primary-bg);
        border: none;
        border-radius: 15px;
        color: var(--text-primary);
        font-size: 1rem;
        font-weight: 500;
        box-shadow: inset 6px 6px 12px var(--shadow-dark),
          inset -6px -6px 12px var(--shadow-light);
        transition: all 0.3s ease;
      }

      input:focus,
      select:focus {
        outline: none;
        box-shadow: inset 8px 8px 16px var(--shadow-dark),
          inset -8px -8px 16px var(--shadow-light),
          0 0 0 3px rgba(102, 126, 234, 0.2);
      }

      button {
        background: var(--primary-bg);
        color: var(--text-primary);
        border: none;
        padding: 14px 28px;
        border-radius: 15px;
        cursor: pointer;
        font-weight: 600;
        transition: all 0.3s ease;
        font-size: 1rem;
        flex-shrink: 0;
        box-shadow: 8px 8px 16px var(--shadow-dark),
          -8px -8px 16px var(--shadow-light);
        position: relative;
        overflow: hidden;
      }

      button::before {
        content: '';
        position: absolute;
        top: 0;
        left: -100%;
        width: 100%;
        height: 100%;
        background: linear-gradient(
          90deg,
          transparent,
          rgba(255, 255, 255, 0.2),
          transparent
        );
        transition: left 0.5s;
      }

      button:hover::before {
        left: 100%;
      }

      button:hover {
        transform: translateY(-3px);
        box-shadow: 12px 12px 24px var(--shadow-dark),
          -12px -12px 24px var(--shadow-light);
      }

      button:active {
        transform: translateY(0);
        box-shadow: inset 6px 6px 12px var(--shadow-dark),
          inset -6px -6px 12px var(--shadow-light);
      }

      button:disabled {
        opacity: 0.6;
        cursor: not-allowed;
        transform: none;
        box-shadow: 4px 4px 8px var(--shadow-dark),
          -4px -4px 8px var(--shadow-light);
      }

      .btn-primary {
        background: var(--accent-gradient);
        color: white;
        padding: 16px 32px;
        font-size: 1.1rem;
        box-shadow: 8px 8px 16px var(--shadow-dark),
          -8px -8px 16px var(--shadow-light),
          inset 0 1px 0 rgba(255, 255, 255, 0.2);
      }

      .btn-primary:hover {
        box-shadow: 12px 12px 24px var(--shadow-dark),
          -12px -12px 24px var(--shadow-light),
          inset 0 1px 0 rgba(255, 255, 255, 0.2),
          0 0 30px rgba(102, 126, 234, 0.3);
      }

      .btn-success {
        background: linear-gradient(
          135deg,
          var(--success-color) 0%,
          #44a08d 100%
        );
        color: white;
        box-shadow: 8px 8px 16px var(--shadow-dark),
          -8px -8px 16px var(--shadow-light),
          inset 0 1px 0 rgba(255, 255, 255, 0.2);
      }

      .progress-container {
        margin: 30px 0;
        animation: progressSlide 0.8s ease 0.8s both;
      }

      @keyframes progressSlide {
        from {
          opacity: 0;
          transform: translateY(20px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      .progress-bar {
        height: 16px;
        background: var(--primary-bg);
        border-radius: 20px;
        overflow: hidden;
        margin-bottom: 15px;
        box-shadow: inset 6px 6px 12px var(--shadow-dark),
          inset -6px -6px 12px var(--shadow-light);
        position: relative;
      }

      .progress-fill {
        height: 100%;
        background: var(--accent-gradient);
        width: 0%;
        transition: width 0.3s ease;
        border-radius: 20px;
        box-shadow: 0 2px 10px rgba(102, 126, 234, 0.3);
        position: relative;
        overflow: hidden;
      }

      .progress-fill::after {
        content: '';
        position: absolute;
        top: 0;
        left: -100%;
        width: 100%;
        height: 100%;
        background: linear-gradient(
          90deg,
          transparent,
          rgba(255, 255, 255, 0.3),
          transparent
        );
        animation: progressShine 2s infinite;
      }

      @keyframes progressShine {
        0% {
          left: -100%;
        }
        100% {
          left: 100%;
        }
      }

      .progress-text {
        text-align: center;
        font-size: 1rem;
        color: var(--text-secondary);
        font-weight: 500;
      }

      .actions {
        display: flex;
        justify-content: center;
        gap: 25px;
        margin-top: 30px;
        animation: actionsSlide 0.8s ease 1s both;
      }

      @keyframes actionsSlide {
        from {
          opacity: 0;
          transform: translateY(20px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      .result-panel {
        text-align: center;
        animation: resultPanelSlide 0.8s ease 1.2s both;
      }

      @keyframes resultPanelSlide {
        from {
          opacity: 0;
          transform: translateY(30px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      .status-message {
        min-height: 35px;
        margin: 20px 0;
        color: var(--accent-color);
        font-weight: 600;
        font-size: 1.1rem;
        transition: all 0.3s ease;
        text-align: center;
      }

      .status-message.processing {
        animation: statusPulse 1.5s ease-in-out infinite;
      }

      @keyframes statusPulse {
        0%,
        100% {
          opacity: 1;
        }
        50% {
          opacity: 0.6;
        }
      }

      .error-message {
        color: var(--danger-color);
        margin: 20px 0;
        min-height: 35px;
        font-weight: 600;
        font-size: 1.1rem;
        animation: errorShake 0.5s ease;
        text-align: center;
      }

      @keyframes errorShake {
        0%,
        100% {
          transform: translateX(0);
        }
        25% {
          transform: translateX(-5px);
        }
        75% {
          transform: translateX(5px);
        }
      }

      .download-section {
        display: none;
        flex-direction: column;
        gap: 20px;
        margin-top: 30px;
        padding: 25px;
        background: var(--primary-bg);
        border-radius: 25px;
        box-shadow: 12px 12px 24px var(--shadow-dark),
          -12px -12px 24px var(--shadow-light);
        border: 2px solid var(--success-color);
        text-align: center;
      }

      .download-section h3 {
        color: var(--success-color);
        margin-bottom: 20px;
        font-size: 1.4rem;
      }

      .instructions {
        background: var(--primary-bg);
        border-radius: 25px;
        padding: 30px;
        margin-top: 40px;
        box-shadow: 10px 10px 20px var(--shadow-dark),
          -10px -10px 20px var(--shadow-light);
        animation: instructionsSlide 0.8s ease 1.4s both;
      }

      @keyframes instructionsSlide {
        from {
          opacity: 0;
          transform: translateY(30px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      .instructions h3 {
        color: var(--accent-color);
        margin-bottom: 20px;
        font-size: 1.4rem;
        font-weight: 600;
      }

      .instructions ol {
        padding-left: 25px;
        margin-bottom: 20px;
      }

      .instructions li {
        margin-bottom: 12px;
        line-height: 1.7;
        color: var(--text-secondary);
        font-weight: 500;
      }

      .instructions p {
        color: var(--text-secondary);
        font-style: italic;
        font-weight: 500;
        padding: 15px;
        background: rgba(102, 126, 234, 0.1);
        border-radius: 15px;
        border-left: 4px solid var(--accent-color);
      }

      footer {
        margin-top: 40px;
        text-align: center;
        color: var(--text-secondary);
        font-size: 0.95rem;
        padding: 25px;
        background: var(--primary-bg);
        border-radius: 20px;
        box-shadow: 6px 6px 12px var(--shadow-dark),
          -6px -6px 12px var(--shadow-light);
        animation: footerFade 0.8s ease 1.6s both;
      }

      @keyframes footerFade {
        from {
          opacity: 0;
        }
        to {
          opacity: 1;
        }
      }

      @media (max-width: 768px) {
        .panels {
          flex-direction: column;
        }

        .container {
          padding: 20px;
        }

        h1 {
          font-size: 2.5rem;
        }
      }
    </style>
  </head>
  <body>
    <div class="container">
      <header>
        <h1>🎬 视频字幕合成工具</h1>
        <p class="subtitle">
          支持LRC、SRT、ASS字幕格式，自动转换并合成到视频中
        </p>
      </header>

      <div class="panels">
        <!-- 视频上传面板 -->
        <div class="panel">
          <div class="panel-title" data-icon="📹">视频上传</div>

          <div class="file-upload" id="videoUploadArea">
            <div class="file-upload-content">
              <span class="file-upload-icon">🎥</span>
              <div class="file-upload-text">点击或拖拽上传视频</div>
              <div class="file-upload-subtext">支持 MP4、AVI、MOV 等格式</div>
              <div class="file-upload-formats">最大支持 500MB</div>
              <input type="file" id="videoInput" accept="video/*" />
            </div>
          </div>

          <div class="video-preview" id="videoPreview">
            <p
              style="
                text-align: center;
                padding: 60px 20px;
                color: var(--text-secondary);
                font-size: 1.1rem;
              "
            >
              📺 视频预览区
            </p>
          </div>
        </div>

        <!-- 字幕上传面板 -->
        <div class="panel">
          <div class="panel-title" data-icon="💬">字幕上传</div>

          <div class="file-upload" id="subtitleUploadArea">
            <div class="file-upload-content">
              <span class="file-upload-icon">📝</span>
              <div class="file-upload-text">点击或拖拽上传字幕</div>
              <div class="file-upload-subtext">支持 LRC、SRT、ASS 格式</div>
              <div class="file-upload-formats">LRC格式将自动转换为SRT</div>
              <input type="file" id="subtitleInput" accept=".lrc,.srt,.ass" />
            </div>
          </div>

          <div class="subtitle-info" id="subtitleInfo" style="display: none">
            <h4>字幕文件信息</h4>
            <p id="subtitleFileName">文件名: -</p>
            <p id="subtitleFileSize">文件大小: -</p>
            <p id="subtitleFileType">文件类型: -</p>
            <p id="subtitleLineCount">字幕条数: -</p>
          </div>
        </div>
      </div>

      <!-- 合成选项 -->
      <div class="panel">
        <div class="panel-title" data-icon="⚙️">合成选项</div>

        <div style="display: flex; gap: 20px; flex-wrap: wrap">
          <div class="form-group" style="flex: 1; min-width: 200px">
            <label for="videoQuality">视频质量</label>
            <select id="videoQuality">
              <option value="23">高质量 (CRF 23)</option>
              <option value="28" selected>标准质量 (CRF 28)</option>
              <option value="32">压缩质量 (CRF 32)</option>
            </select>
          </div>

          <div class="form-group" style="flex: 1; min-width: 200px">
            <label for="videoCodec">视频编码</label>
            <select id="videoCodec">
              <option value="libx264" selected>H.264 (兼容性好)</option>
              <option value="libx265">H.265 (文件更小)</option>
            </select>
          </div>

          <div class="form-group" style="flex: 1; min-width: 200px">
            <label for="subtitleStyle">字幕样式</label>
            <select id="subtitleStyle">
              <option value="default" selected>默认样式</option>
              <option value="bold">加粗样式</option>
              <option value="shadow">阴影样式</option>
            </select>
          </div>

          <div class="form-group" style="flex: 1; min-width: 200px">
            <label for="fontSizeMode">字体大小</label>
            <select id="fontSizeMode">
              <option value="auto" selected>自动适配分辨率</option>
              <option value="custom">自定义大小</option>
            </select>
            <div
              style="
                margin-top: 6px;
                font-size: 0.75rem;
                color: var(--warning-color);
                text-align: center;
              "
            >
              ⚠️ 仅适用于SRT字幕
            </div>
          </div>

          <div
            class="form-group"
            id="customFontSizeGroup"
            style="flex: 1; min-width: 200px; display: none"
          >
            <label for="customFontSize">字体大小 (px)</label>
            <input
              type="range"
              id="customFontSize"
              min="16"
              max="80"
              value="36"
              step="2"
            />
            <div
              style="
                text-align: center;
                margin-top: 5px;
                font-size: 0.9rem;
                color: var(--text-secondary);
              "
            >
              <span id="fontSizeValue">36</span> px
            </div>
            <div
              style="
                text-align: center;
                margin-top: 8px;
                font-size: 0.8rem;
                color: var(--warning-color);
                background: rgba(254, 202, 87, 0.1);
                padding: 6px 12px;
                border-radius: 12px;
                border-left: 3px solid var(--warning-color);
              "
            >
              ✅ 适用于所有字幕格式，ASS字幕会自动规范化
            </div>
          </div>
        </div>
      </div>

      <!-- 进度显示 -->
      <div class="progress-container">
        <div class="progress-bar">
          <div class="progress-fill" id="progressFill"></div>
        </div>
        <div class="progress-text" id="progressText">等待开始...</div>
      </div>

      <!-- 状态消息 -->
      <div class="status-message" id="statusMessage"></div>
      <div class="error-message" id="errorMessage"></div>

      <!-- 操作按钮 -->
      <div class="actions">
        <button type="button" id="processBtn" class="btn-primary" disabled>
          🚀 开始合成
        </button>
        <button type="button" id="resetBtn">🔄 重置</button>
      </div>

      <!-- 日志下载区域 -->
      <div class="log-section" style="text-align: center; margin: 20px 0">
        <button type="button" id="downloadLogBtn" class="btn-primary">
          📋 下载处理日志
        </button>
      </div>

      <!-- 下载区域 -->
      <div class="download-section" id="downloadSection">
        <h3>✅ 合成完成</h3>

        <!-- 视频预览区域 -->
        <div class="preview-section" style="margin: 20px 0; text-align: center">
          <h4>🎬 预览合成视频</h4>
          <video
            id="previewVideo"
            controls
            style="
              max-width: 100%;
              max-height: 400px;
              border-radius: 8px;
              box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
            "
          >
            您的浏览器不支持视频播放。
          </video>
        </div>

        <div
          style="
            display: flex;
            gap: 10px;
            flex-wrap: wrap;
            justify-content: center;
          "
        >
          <button type="button" id="downloadBtn" class="btn-success">
            📥 下载合成视频
          </button>
        </div>
      </div>

      <!-- 使用说明 -->
      <div class="instructions">
        <h3>📖 使用说明</h3>
        <ol>
          <li>上传您的视频文件（支持MP4、AVI、MOV等格式）</li>
          <li>上传字幕文件（支持LRC、SRT、ASS格式）</li>
          <li>选择合成选项（视频质量、编码格式、字幕样式）</li>
          <li>点击"开始合成"按钮进行处理</li>
          <li>等待处理完成后下载合成后的视频</li>
        </ol>
        <p>
          💡
          提示：LRC格式的字幕文件将自动转换为SRT格式进行合成，确保最佳兼容性。
        </p>
      </div>

      <footer>
        <p>🎬 视频字幕合成工具 - 让您的视频更精彩</p>
      </footer>
    </div>

    <script>
      // 全局变量
      const { createFFmpeg, fetchFile } = FFmpeg
      let ffmpeg = null
      let videoFile = null
      let subtitleFile = null
      let subtitleContent = ''
      let subtitleFormat = ''
      let processingLogs = [] // 存储处理日志

      // DOM 元素
      const videoInput = document.getElementById('videoInput')
      const subtitleInput = document.getElementById('subtitleInput')
      const videoUploadArea = document.getElementById('videoUploadArea')
      const subtitleUploadArea = document.getElementById('subtitleUploadArea')
      const videoPreview = document.getElementById('videoPreview')
      const subtitleInfo = document.getElementById('subtitleInfo')
      const processBtn = document.getElementById('processBtn')
      const resetBtn = document.getElementById('resetBtn')
      const downloadBtn = document.getElementById('downloadBtn')
      const downloadLogBtn = document.getElementById('downloadLogBtn')
      const downloadSection = document.getElementById('downloadSection')
      const previewVideo = document.getElementById('previewVideo')
      const progressFill = document.getElementById('progressFill')
      const progressText = document.getElementById('progressText')
      const statusMessage = document.getElementById('statusMessage')
      const errorMessage = document.getElementById('errorMessage')
      const fontSizeMode = document.getElementById('fontSizeMode')
      const customFontSize = document.getElementById('customFontSize')
      const customFontSizeGroup = document.getElementById('customFontSizeGroup')
      const fontSizeValue = document.getElementById('fontSizeValue')

      // 初始化
      async function init() {
        try {
          statusMessage.textContent = '🔄 正在初始化FFmpeg...'

          // 检查FFmpeg是否可用
          if (typeof createFFmpeg === 'undefined') {
            throw new Error('FFmpeg库未加载')
          }

          ffmpeg = createFFmpeg({
            log: true,
          })

          // 设置日志收集
          ffmpeg.setLogger(({ type, message }) => {
            const timestamp = new Date().toLocaleTimeString()
            const logEntry = `[${timestamp}] [${type}] ${message}`
            processingLogs.push(logEntry)
            console.log(logEntry)
          })

          ffmpeg.setProgress(({ ratio }) => {
            const percent = Math.round(ratio * 100)
            updateProgress(percent, `处理中... ${percent}%`)
          })

          await ffmpeg.load()
          statusMessage.textContent = '✅ FFmpeg初始化完成'

          setupEventListeners()
        } catch (error) {
          console.error('FFmpeg初始化失败:', error)
          showError('❌ FFmpeg初始化失败，请刷新页面重试')

          // 如果FFmpeg初始化失败，仍然设置事件监听器以便用户可以上传文件
          setupEventListeners()
        }
      }

      // 设置事件监听器
      function setupEventListeners() {
        // 视频文件上传
        videoInput.addEventListener('change', handleVideoUpload)
        videoUploadArea.addEventListener('click', (e) => {
          if (e.target !== videoInput) {
            videoInput.click()
          }
        })
        videoUploadArea.addEventListener('dragover', handleDragOver)
        videoUploadArea.addEventListener('drop', handleVideoDrop)

        // 字幕文件上传
        subtitleInput.addEventListener('change', handleSubtitleUpload)
        subtitleUploadArea.addEventListener('click', (e) => {
          if (e.target !== subtitleInput) {
            subtitleInput.click()
          }
        })
        subtitleUploadArea.addEventListener('dragover', handleDragOver)
        subtitleUploadArea.addEventListener('drop', handleSubtitleDrop)

        // 按钮事件
        processBtn.addEventListener('click', processVideo)
        resetBtn.addEventListener('click', resetAll)
        downloadBtn.addEventListener('click', downloadVideo)
        downloadLogBtn.addEventListener('click', downloadLogs)

        // 字体大小相关事件
        fontSizeMode.addEventListener('change', handleFontSizeModeChange)
        customFontSize.addEventListener('input', handleCustomFontSizeChange)
      }

      // 处理拖拽
      function handleDragOver(event) {
        event.preventDefault()
        event.currentTarget.classList.add('dragover')
      }

      function handleVideoDrop(event) {
        event.preventDefault()
        event.currentTarget.classList.remove('dragover')
        const files = event.dataTransfer.files
        if (files.length > 0) {
          handleVideoFile(files[0])
        }
      }

      function handleSubtitleDrop(event) {
        event.preventDefault()
        event.currentTarget.classList.remove('dragover')
        const files = event.dataTransfer.files
        if (files.length > 0) {
          handleSubtitleFile(files[0])
        }
      }

      // 处理视频上传
      function handleVideoUpload(event) {
        const file = event.target.files[0]
        if (file) {
          handleVideoFile(file)
        }
      }

      async function handleVideoFile(file) {
        if (!file.type.startsWith('video/')) {
          showError('❌ 请选择视频文件')
          return
        }

        if (file.size > 500 * 1024 * 1024) {
          showError('❌ 视频文件大小不能超过500MB')
          return
        }

        videoFile = file

        // 显示视频预览
        const videoURL = URL.createObjectURL(file)
        videoPreview.innerHTML = `<video controls src="${videoURL}"></video>`

        // 获取视频分辨率并自动设置字体大小
        try {
          const videoElement = videoPreview.querySelector('video')
          const resolution = await getVideoResolution(videoElement)

          // 如果是自动模式，根据分辨率计算字体大小
          if (fontSizeMode.value === 'auto') {
            const calculatedSize = calculateFontSizeByResolution(
              resolution.width,
              resolution.height
            )
            customFontSize.value = calculatedSize
            fontSizeValue.textContent = calculatedSize
            statusMessage.textContent = `📹 已加载视频: ${file.name} (${resolution.width}x${resolution.height}, 字体大小: ${calculatedSize}px)`
          } else {
            statusMessage.textContent = `📹 已加载视频: ${file.name} (${resolution.width}x${resolution.height})`
          }
        } catch (error) {
          console.warn('获取视频分辨率失败:', error)
          // 获取失败时，自动切换到自定义模式，让用户手动设置
          fontSizeMode.value = 'custom'
          customFontSize.value = 36
          fontSizeValue.textContent = '36'
          handleFontSizeModeChange() // 显示自定义字体大小控件
          statusMessage.textContent = `📹 已加载视频: ${file.name} (无法获取分辨率，请手动设置字体大小)`
        }

        updateProcessButton()
      }

      // 处理字幕上传
      function handleSubtitleUpload(event) {
        const file = event.target.files[0]
        if (file) {
          handleSubtitleFile(file)
        }
      }

      async function handleSubtitleFile(file) {
        const fileName = file.name.toLowerCase()

        if (
          !fileName.endsWith('.lrc') &&
          !fileName.endsWith('.srt') &&
          !fileName.endsWith('.ass')
        ) {
          showError('❌ 请选择LRC、SRT或ASS格式的字幕文件')
          return
        }

        if (file.size > 5 * 1024 * 1024) {
          showError('❌ 字幕文件大小不能超过5MB')
          return
        }

        subtitleFile = file

        try {
          subtitleContent = await readFileAsText(file)

          // 确定字幕格式
          if (fileName.endsWith('.lrc')) {
            subtitleFormat = 'lrc'
            // 转换LRC为SRT
            subtitleContent = convertLrcToSrt(subtitleContent)
          } else if (fileName.endsWith('.srt')) {
            subtitleFormat = 'srt'
          } else if (fileName.endsWith('.ass')) {
            subtitleFormat = 'ass'
          }

          // 显示字幕信息
          displaySubtitleInfo(file)

          statusMessage.textContent = `📝 已加载字幕: ${file.name}${
            subtitleFormat === 'lrc' ? ' (已转换为SRT)' : ''
          }`
          updateProcessButton()
        } catch (error) {
          console.error('字幕文件读取失败:', error)
          showError('❌ 字幕文件读取失败')
        }
      }

      // 显示字幕信息
      function displaySubtitleInfo(file) {
        const lineCount = subtitleContent
          .split('\n')
          .filter((line) => line.trim()).length

        document.getElementById(
          'subtitleFileName'
        ).textContent = `文件名: ${file.name}`
        document.getElementById(
          'subtitleFileSize'
        ).textContent = `文件大小: ${formatFileSize(file.size)}`
        document.getElementById(
          'subtitleFileType'
        ).textContent = `文件类型: ${subtitleFormat.toUpperCase()}${
          subtitleFormat === 'lrc' ? ' → SRT' : ''
        }`
        document.getElementById(
          'subtitleLineCount'
        ).textContent = `字幕条数: ${Math.floor(lineCount / 3)}`

        subtitleInfo.style.display = 'block'
      }

      // 读取文件为文本
      function readFileAsText(file) {
        return new Promise((resolve, reject) => {
          const reader = new FileReader()
          reader.onload = (e) => resolve(e.target.result)
          reader.onerror = reject
          reader.readAsText(file, 'UTF-8')
        })
      }

      // LRC转SRT格式
      function convertLrcToSrt(lrcContent) {
        const lines = lrcContent.split('\n')
        const subtitles = []

        lines.forEach((line) => {
          const match = line.match(/\[(\d{2}):(\d{2})\.(\d{2,3})\](.+)/)
          if (match) {
            const minutes = parseInt(match[1])
            const seconds = parseInt(match[2])
            const milliseconds = parseInt(match[3].padEnd(3, '0'))
            const text = match[4].trim()

            if (
              text &&
              !text.includes('作词') &&
              !text.includes('作曲') &&
              !text.includes('编曲') &&
              !text.includes('演唱')
            ) {
              const startTime = minutes * 60 + seconds + milliseconds / 1000
              subtitles.push({ startTime, text })
            }
          }
        })

        // 转换为SRT格式
        let srtContent = ''
        subtitles.forEach((subtitle, index) => {
          const nextSubtitle = subtitles[index + 1]
          const startTime = formatSrtTime(subtitle.startTime)
          const endTime = nextSubtitle
            ? formatSrtTime(nextSubtitle.startTime - 0.1)
            : formatSrtTime(subtitle.startTime + 3)

          srtContent += `${index + 1}\n`
          srtContent += `${startTime} --> ${endTime}\n`
          srtContent += `${subtitle.text}\n\n`
        })

        return srtContent
      }

      // 格式化SRT时间
      function formatSrtTime(seconds) {
        const hours = Math.floor(seconds / 3600)
        const minutes = Math.floor((seconds % 3600) / 60)
        const secs = Math.floor(seconds % 60)
        const ms = Math.floor((seconds % 1) * 1000)

        return `${hours.toString().padStart(2, '0')}:${minutes
          .toString()
          .padStart(2, '0')}:${secs.toString().padStart(2, '0')},${ms
          .toString()
          .padStart(3, '0')}`
      }

      // 更新处理按钮状态
      function updateProcessButton() {
        processBtn.disabled = !(videoFile && subtitleFile)
      }

      // 处理字体大小模式切换
      async function handleFontSizeModeChange() {
        const isCustomMode = fontSizeMode.value === 'custom'
        customFontSizeGroup.style.display = isCustomMode ? 'block' : 'none'

        // 如果切换到自动模式且已有视频文件，重新计算字体大小
        if (!isCustomMode && videoFile) {
          try {
            const videoElement = videoPreview.querySelector('video')
            if (videoElement) {
              const resolution = await getVideoResolution(videoElement)
              const calculatedSize = calculateFontSizeByResolution(
                resolution.width,
                resolution.height
              )
              customFontSize.value = calculatedSize
              fontSizeValue.textContent = calculatedSize
              statusMessage.textContent = `📹 视频: ${videoFile.name} (${resolution.width}x${resolution.height}, 字体大小: ${calculatedSize}px)`
            }
          } catch (error) {
            console.warn('重新计算字体大小失败:', error)
            // 如果获取失败，保持当前值或使用默认值
            if (!customFontSize.value) {
              customFontSize.value = 36
              fontSizeValue.textContent = '36'
            }
          }
        }
      }

      // 处理自定义字体大小变化
      function handleCustomFontSizeChange() {
        fontSizeValue.textContent = customFontSize.value
      }

      // 根据视频分辨率计算字体大小
      function calculateFontSizeByResolution(width, height) {
        // 基于视频高度计算字体大小，确保在不同分辨率下字幕大小合适
        // 720p -> 32px, 1080p -> 48px, 1440p -> 64px, 4K -> 96px
        const baseHeight = 720
        const baseFontSize = 32
        const scaleFactor = height / baseHeight

        // 限制字体大小范围在16-120px之间
        const calculatedSize = Math.round(baseFontSize * scaleFactor)
        return Math.max(16, Math.min(120, calculatedSize))
      }

      // 获取视频分辨率
      async function getVideoResolution(videoElement) {
        return new Promise((resolve, reject) => {
          let attempts = 0
          const maxAttempts = 50 // 最多尝试5秒

          const checkResolution = () => {
            attempts++

            if (videoElement.videoWidth && videoElement.videoHeight) {
              resolve({
                width: videoElement.videoWidth,
                height: videoElement.videoHeight,
              })
            } else if (attempts >= maxAttempts) {
              // 超时后拒绝Promise
              reject(new Error('获取视频分辨率超时'))
            } else {
              // 如果还没有加载完成，等待一下再检查
              setTimeout(checkResolution, 100)
            }
          }
          checkResolution()
        })
      }

      // 处理视频
      async function processVideo() {
        if (!videoFile || !subtitleFile) {
          showError('❌ 请先上传视频和字幕文件')
          return
        }

        try {
          // 清空之前的日志
          processingLogs = []
          processingLogs.push(
            `[${new Date().toLocaleTimeString()}] [info] 开始处理视频: ${
              videoFile.name
            }`
          )
          processingLogs.push(
            `[${new Date().toLocaleTimeString()}] [info] 字幕文件: ${
              subtitleFile.name
            } (${subtitleFormat})`
          )

          processBtn.disabled = true
          resetBtn.disabled = true
          downloadSection.style.display = 'none'

          statusMessage.textContent = '🚀 开始处理视频...'
          statusMessage.classList.add('processing')

          // 写入文件到FFmpeg文件系统
          const videoData = new Uint8Array(await videoFile.arrayBuffer())
          const videoExt = getFileExtension(videoFile.name)
          const inputVideoName = `input.${videoExt}`

          ffmpeg.FS('writeFile', inputVideoName, videoData)

          // 获取视频分辨率（用于ASS字幕规范化）
          let videoResolution = null
          try {
            // 使用HTML5 video元素获取分辨率
            const tempVideo = document.createElement('video')
            tempVideo.src = URL.createObjectURL(videoFile)

            await new Promise((resolve, reject) => {
              tempVideo.onloadedmetadata = () => {
                videoResolution = {
                  width: tempVideo.videoWidth,
                  height: tempVideo.videoHeight,
                }
                resolve()
              }
              tempVideo.onerror = () => {
                // 如果失败，使用默认分辨率
                videoResolution = { width: 1920, height: 1080 }
                resolve()
              }
              setTimeout(() => {
                if (!videoResolution) {
                  videoResolution = { width: 1920, height: 1080 }
                  resolve()
                }
              }, 3000) // 3秒超时
            })

            URL.revokeObjectURL(tempVideo.src)
            processingLogs.push(
              `[${new Date().toLocaleTimeString()}] [info] 视频分辨率: ${
                videoResolution.width
              }x${videoResolution.height}`
            )
          } catch (error) {
            videoResolution = { width: 1920, height: 1080 }
            processingLogs.push(
              `[${new Date().toLocaleTimeString()}] [warning] 分辨率检测失败，使用默认值: 1920x1080`
            )
          }

          // 获取字体大小（用于字幕处理）
          const fontSize = parseInt(customFontSize.value) || 36
          processingLogs.push(
            `[${new Date().toLocaleTimeString()}] [info] 使用字体大小: ${fontSize}px (${
              fontSizeMode.value === 'auto' ? '自动计算' : '自定义设置'
            })`
          )

          // 写入字幕文件
          const subtitleFileName =
            subtitleFormat === 'ass' ? 'subtitle.ass' : 'subtitle.srt'

          // 如果是ASS格式，进行规范化处理
          let processedSubtitleContent = subtitleContent
          if (subtitleFormat === 'ass' && videoResolution) {
            processedSubtitleContent = normalizeAss(
              subtitleContent,
              videoResolution.width,
              videoResolution.height,
              fontSize
            )
            processingLogs.push(
              `[${new Date().toLocaleTimeString()}] [info] 已规范化ASS字幕 (PlayResX=${
                videoResolution.width
              }, PlayResY=${videoResolution.height}, FontSize=${fontSize})`
            )
          }

          ffmpeg.FS(
            'writeFile',
            subtitleFileName,
            new TextEncoder().encode(processedSubtitleContent)
          )

          // 写入字体文件到FFmpeg文件系统
          try {
            const fontResponse = await fetch('./SourceHanSansCN-Regular.ttf')
            const fontData = new Uint8Array(await fontResponse.arrayBuffer())
            ffmpeg.FS('writeFile', 'SourceHanSansCN-Regular.ttf', fontData)
          } catch (e) {
            console.warn('字体文件加载失败，使用默认字体:', e)
          }

          // 获取合成选项
          const quality = document.getElementById('videoQuality').value
          const codec = document.getElementById('videoCodec').value
          const style = document.getElementById('subtitleStyle').value

          // 构建FFmpeg命令
          const outputName = 'output.mp4'
          let ffmpegArgs = ['-i', inputVideoName]

          // 根据字幕格式使用不同的滤镜配置
          let subtitleFilter = `subtitles=${subtitleFileName}:fontsdir=.`

          if (subtitleFormat === 'ass') {
            // ASS格式使用规范化后的字体大小
            subtitleFilter += `:force_style='FontName=Source Han Sans CN,FontSize=${fontSize},PrimaryColour=0xffffff,OutlineColour=0x000000,BackColour=0x80000000,Outline=2,Shadow=1,MarginV=50'`
          } else {
            // SRT和LRC格式支持完整样式配置
            let forceStyle = `FontName=Source Han Sans CN,FontSize=${fontSize},PrimaryColour=0xffffff,OutlineColour=0x000000,BackColour=0x80000000,Outline=2,Shadow=1`

            if (style === 'bold') {
              forceStyle += ',Bold=1'
            } else if (style === 'shadow') {
              forceStyle += ',Shadow=2,Outline=3'
            }

            subtitleFilter += `:force_style='${forceStyle}'`
          }

          ffmpegArgs.push('-vf', subtitleFilter)

          // 添加编码参数
          ffmpegArgs.push(
            '-c:v',
            codec,
            '-crf',
            quality,
            '-c:a',
            'copy',
            outputName
          )

          // 执行FFmpeg命令
          await ffmpeg.run(...ffmpegArgs)

          // 读取输出文件
          const outputData = ffmpeg.FS('readFile', outputName)

          // 创建下载链接
          const blob = new Blob([outputData.buffer], { type: 'video/mp4' })
          const url = URL.createObjectURL(blob)

          downloadBtn.onclick = () => {
            const a = document.createElement('a')
            a.href = url
            a.download = `${getFileNameWithoutExt(
              videoFile.name
            )}_with_subtitles.mp4`
            a.click()
          }

          // 设置预览视频
          previewVideo.src = url
          previewVideo.load() // 重新加载视频元素

          // 显示下载区域
          downloadSection.style.display = 'flex'

          statusMessage.textContent = '✅ 视频合成完成！'
          statusMessage.classList.remove('processing')

          // 清理FFmpeg文件系统
          try {
            ffmpeg.FS('unlink', inputVideoName)
            ffmpeg.FS('unlink', subtitleFileName)
            ffmpeg.FS('unlink', outputName)
            ffmpeg.FS('unlink', 'SourceHanSansCN-Regular.ttf')
          } catch (e) {
            console.warn('清理临时文件失败:', e)
          }
        } catch (error) {
          console.error('视频处理失败:', error)
          showError('❌ 视频处理失败: ' + error.message)
          statusMessage.classList.remove('processing')
        } finally {
          processBtn.disabled = false
          resetBtn.disabled = false
          updateProgress(0, '等待开始...')
        }
      }

      // 重置所有
      function resetAll() {
        videoFile = null
        subtitleFile = null
        subtitleContent = ''
        subtitleFormat = ''
        processingLogs = [] // 清空日志

        videoInput.value = ''
        subtitleInput.value = ''

        videoPreview.innerHTML = `
          <p style="text-align: center; padding: 60px 20px; color: var(--text-secondary); font-size: 1.1rem;">
            📺 视频预览区
          </p>
        `

        subtitleInfo.style.display = 'none'
        downloadSection.style.display = 'none'

        // 清理预览视频
        previewVideo.src = ''
        previewVideo.load()

        statusMessage.textContent = ''
        statusMessage.classList.remove('processing')
        errorMessage.textContent = ''

        updateProgress(0, '等待开始...')
        updateProcessButton()
      }

      // 下载视频
      function downloadVideo() {
        // 下载逻辑在processVideo中已处理
      }

      // 更新进度
      function updateProgress(percent, text) {
        progressFill.style.width = `${percent}%`
        progressText.textContent = text
      }

      // 显示错误
      function showError(message) {
        errorMessage.textContent = message
        setTimeout(() => {
          errorMessage.textContent = ''
        }, 5000)
      }

      // 下载日志
      function downloadLogs() {
        if (processingLogs.length === 0) {
          showError('❌ 暂无处理日志')
          return
        }

        const logContent = processingLogs.join('\n')
        const blob = new Blob([logContent], {
          type: 'text/plain;charset=utf-8',
        })
        const url = URL.createObjectURL(blob)

        const a = document.createElement('a')
        a.href = url
        a.download = `video-subtitle-merge-log-${new Date()
          .toISOString()
          .slice(0, 19)
          .replace(/:/g, '-')}.txt`
        document.body.appendChild(a)
        a.click()
        document.body.removeChild(a)
        URL.revokeObjectURL(url)
      }

      // 规范化ASS字幕
      function normalizeAss(
        assContent,
        videoWidth,
        videoHeight,
        targetFontSize
      ) {
        // 计算降级后的分辨率
        let downgradedWidth = videoWidth
        let downgradedHeight = videoHeight

        // 根据原始分辨率降级到下一级标准分辨率
        if (videoWidth >= 3840 && videoHeight >= 2160) {
          // 4K (3840x2160) -> 2K (2560x1440)
          downgradedWidth = 2560
          downgradedHeight = 1440
        } else if (videoWidth >= 2560 && videoHeight >= 1440) {
          // 2K (2560x1440) -> 1080P (1920x1080)
          downgradedWidth = 1920
          downgradedHeight = 1080
        } else if (videoWidth >= 1920 && videoHeight >= 1080) {
          // 1080P (1920x1080) -> 1440P (1440x810)
          downgradedWidth = 1440
          downgradedHeight = 810
        } else if (videoWidth >= 1440 && videoHeight >= 810) {
          // 1440P (1440x810) -> 720P (1280x720)
          downgradedWidth = 1280
          downgradedHeight = 720
        } else if (videoWidth >= 1280 && videoHeight >= 720) {
          // 720P (1280x720) -> 480P (854x480)
          downgradedWidth = 854
          downgradedHeight = 480
        } else if (videoWidth >= 854 && videoHeight >= 480) {
          // 480P (854x480) -> 360P (640x360)
          downgradedWidth = 640
          downgradedHeight = 360
        } else {
          // 更小分辨率保持不变
          downgradedWidth = videoWidth
          downgradedHeight = videoHeight
        }

        const lines = assContent.split('\n')
        let result = []
        let inScriptInfo = false
        let inV4Styles = false
        let inEvents = false

        for (let line of lines) {
          const trimmedLine = line.trim()

          // 处理[Script Info]部分
          if (trimmedLine === '[Script Info]') {
            inScriptInfo = true
            inV4Styles = false
            inEvents = false
            result.push(line)
            continue
          }

          // 处理[V4+ Styles]部分
          if (trimmedLine === '[V4+ Styles]') {
            inScriptInfo = false
            inV4Styles = true
            inEvents = false
            result.push(line)
            continue
          }

          // 处理[Events]部分
          if (trimmedLine === '[Events]') {
            inScriptInfo = false
            inV4Styles = false
            inEvents = true
            result.push(line)
            continue
          }

          // 处理其他section
          if (trimmedLine.startsWith('[') && trimmedLine.endsWith(']')) {
            inScriptInfo = false
            inV4Styles = false
            inEvents = false
            result.push(line)
            continue
          }

          // 在Script Info中重写PlayResX和PlayResY为降级后的分辨率
          if (inScriptInfo) {
            if (trimmedLine.startsWith('PlayResX:')) {
              result.push(`PlayResX: ${downgradedWidth}`)
              continue
            }
            if (trimmedLine.startsWith('PlayResY:')) {
              result.push(`PlayResY: ${downgradedHeight}`)
              continue
            }
            result.push(line)
            continue
          }

          // 在V4+ Styles中统一字体大小和样式
          if (inV4Styles && trimmedLine.startsWith('Style:')) {
            const parts = line.split(',')
            if (parts.length >= 23) {
              // 统一字体大小和字体名称
              parts[2] = targetFontSize.toString() // FontSize
              parts[1] = 'Source Han Sans CN' // FontName
              parts[3] = '100' // ScaleX
              parts[4] = '100' // ScaleY
              result.push(parts.join(','))
              continue
            }
          }

          // 在Events中清理内联字体大小标签并添加默认渐入渐出
          if (
            inEvents &&
            (trimmedLine.startsWith('Dialogue:') ||
              trimmedLine.startsWith('Comment:'))
          ) {
            // 清理内联的\fs、\fscx、\fscy、\fn、\r标签，但保留\move、\fad等动态效果
            let processedLine = line

            // 清理字体大小相关的内联标签
            processedLine = processedLine.replace(/\\fs\d+/g, '') // 清理\fs<size>
            processedLine = processedLine.replace(/\\fscx\d+/g, '') // 清理\fscx<scale>
            processedLine = processedLine.replace(/\\fscy\d+/g, '') // 清理\fscy<scale>
            processedLine = processedLine.replace(/\\fn[^\\}]+/g, '') // 清理\fn<fontname>
            processedLine = processedLine.replace(/\\r[^\\}]+/g, '') // 清理\r<style>

            // 清理可能的多余空格和逗号
            processedLine = processedLine.replace(/\{,+\}/g, '{}') // 清理空的大括号
            processedLine = processedLine.replace(/\{[^}]*\}/g, (match) => {
              // 如果大括号内只剩空格，清理掉
              const content = match.slice(1, -1).trim()
              return content ? match : ''
            })

            // 为每行添加默认的渐入渐出效果（500ms淡入，500ms淡出）
            processedLine = processedLine.replace(
              /\{([^}]*)\}/g,
              (match, content) => {
                // 如果已有fad效果，不重复添加
                if (content.includes('\\fad')) {
                  return match
                }
                // 如果已有其他效果，在现有效果后添加fad
                if (content.trim()) {
                  return `{${content}\\fad(500,500)}`
                }
                // 如果没有效果，直接添加fad
                return '{\\fad(500,500)}'
              }
            )

            // 如果没有大括号，添加包含fad的大括号
            if (!processedLine.includes('{')) {
              const lastCommaIndex = processedLine.lastIndexOf(',')
              if (lastCommaIndex !== -1) {
                const beforeText = processedLine.substring(
                  0,
                  lastCommaIndex + 1
                )
                const afterText = processedLine.substring(lastCommaIndex + 1)
                processedLine = `${beforeText}{\\fad(500,500)}${afterText}`
              }
            }

            result.push(processedLine)
            continue
          }

          // 其他行保持不变
          result.push(line)
        }

        return result.join('\n')
      }

      // 工具函数
      function getFileExtension(filename) {
        return filename.split('.').pop().toLowerCase()
      }

      function getFileNameWithoutExt(filename) {
        return filename.substring(0, filename.lastIndexOf('.'))
      }

      function formatFileSize(bytes) {
        if (bytes === 0) return '0 Bytes'
        const k = 1024
        const sizes = ['Bytes', 'KB', 'MB', 'GB']
        const i = Math.floor(Math.log(bytes) / Math.log(k))
        return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
      }

      // 页面加载完成后初始化
      window.addEventListener('load', init)
    </script>
  </body>
</html>
